Add support for multiple -p options to `cargo clean`
authorFlorian Hahn <flo@fhahn.com>
Tue, 15 Sep 2015 22:29:38 +0000 (00:29 +0200)
committerFlorian Hahn <flo@fhahn.com>
Wed, 30 Sep 2015 19:30:53 +0000 (21:30 +0200)
src/bin/clean.rs
src/cargo/ops/cargo_clean.rs
tests/test_cargo_clean.rs

index 18c6111e56e7014394e875337a76081e2aab8178..8aea04d35a70cc0eeb442549cc09c47a55bf9694 100644 (file)
@@ -6,7 +6,7 @@ use cargo::util::important_paths::{find_root_manifest_for_cwd};
 
 #[derive(RustcDecodable)]
 struct Options {
-    flag_package: Option<String>,
+    flag_package: Vec<String>,
     flag_target: Option<String>,
     flag_manifest_path: Option<String>,
     flag_verbose: bool,
@@ -21,13 +21,13 @@ Usage:
     cargo clean [options]
 
 Options:
-    -h, --help               Print this message
-    -p SPEC, --package SPEC  Package to clean artifacts for
-    --manifest-path PATH     Path to the manifest to the package to clean
-    --target TRIPLE          Target triple to clean output for (default all)
-    -v, --verbose            Use verbose output
-    -q, --quiet              No output printed to stdout
-    --color WHEN             Coloring: auto, always, never
+    -h, --help                   Print this message
+    -p SPEC, --package SPEC ...  Package to clean artifacts for
+    --manifest-path PATH         Path to the manifest to the package to clean
+    --target TRIPLE              Target triple to clean output for (default all)
+    -v, --verbose                Use verbose output
+    -q, --quiet                  No output printed to stdout
+    --color WHEN                 Coloring: auto, always, never
 
 If the --package argument is given, then SPEC is a package id specification
 which indicates which package's artifacts should be cleaned out. If it is not
@@ -43,7 +43,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
     let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
     let opts = ops::CleanOptions {
         config: config,
-        spec: options.flag_package.as_ref().map(|s| &s[..]),
+        spec: &options.flag_package,
         target: options.flag_target.as_ref().map(|s| &s[..]),
     };
     ops::clean(&root, &opts).map(|_| None).map_err(|err| {
index c3bc268278be17a6e4d0352ef1b28fa312649aad..06542b364c2e93fd6692b807e0aaddb12335f3f8 100644 (file)
@@ -9,7 +9,7 @@ use util::{CargoResult, human, ChainError, Config};
 use ops::{self, Layout, Context, BuildConfig, Kind};
 
 pub struct CleanOptions<'a> {
-    pub spec: Option<&'a str>,
+    pub spec: &'a [String],
     pub target: Option<&'a str>,
     pub config: &'a Config,
 }
@@ -21,28 +21,19 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
 
     // If we have a spec, then we need to delete some packages, otherwise, just
     // remove the whole target directory and be done with it!
-    let spec = match opts.spec {
-        Some(spec) => spec,
-        None => return rm_rf(&target_dir),
-    };
+    if opts.spec.len() == 0 {
+        return rm_rf(&target_dir);
+    }
 
-    // Load the lockfile (if one's available), and resolve spec to a pkgid
+    // Load the lockfile (if one's available)
     let lockfile = root.root().join("Cargo.lock");
     let source_id = root.package_id().source_id();
     let resolve = match try!(ops::load_lockfile(&lockfile, source_id)) {
         Some(resolve) => resolve,
         None => return Err(human("A Cargo.lock must exist before cleaning"))
     };
-    let pkgid = try!(resolve.query(spec));
-
-    // Translate the PackageId to a Package
-    let pkg = {
-        let mut source = pkgid.source_id().load(opts.config);
-        try!(source.update());
-        (try!(source.get(&[pkgid.clone()]))).into_iter().next().unwrap()
-    };
 
-    // Create a compilation context to have access to information like target
+     // Create a compilation context to have access to information like target
     // filenames and such
     let srcs = SourceMap::new();
     let pkgs = PackageSet::new(&[]);
@@ -52,17 +43,29 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
                                None, BuildConfig::default(),
                                &profiles));
 
-    // And finally, clean everything out!
-    for target in pkg.targets().iter() {
-        // TODO: `cargo clean --release`
-        let layout = Layout::new(opts.config, &root, opts.target, "debug");
-        try!(rm_rf(&layout.fingerprint(&pkg)));
-        let profiles = [Profile::default_dev(), Profile::default_test()];
-        for profile in profiles.iter() {
-            for filename in try!(cx.target_filenames(&pkg, target, profile,
-                                                     Kind::Target)).iter() {
-                try!(rm_rf(&layout.dest().join(&filename)));
-                try!(rm_rf(&layout.deps().join(&filename)));
+    // resolve package specs and remove the corresponding packages
+    for spec in opts.spec {
+        let pkgid = try!(resolve.query(spec));
+
+        // Translate the PackageId to a Package
+        let pkg = {
+            let mut source = pkgid.source_id().load(opts.config);
+            try!(source.update());
+            (try!(source.get(&[pkgid.clone()]))).into_iter().next().unwrap()
+        };
+
+        // And finally, clean everything out!
+        for target in pkg.targets().iter() {
+            // TODO: `cargo clean --release`
+            let layout = Layout::new(opts.config, &root, opts.target, "debug");
+            try!(rm_rf(&layout.fingerprint(&pkg)));
+            let profiles = [Profile::default_dev(), Profile::default_test()];
+            for profile in profiles.iter() {
+                for filename in try!(cx.target_filenames(&pkg, target, profile,
+                                                         Kind::Target)).iter() {
+                    try!(rm_rf(&layout.dest().join(&filename)));
+                    try!(rm_rf(&layout.deps().join(&filename)));
+                }
             }
         }
     }
index 9ccd8f7314f40ba6a6aa24ffd26c30dbe411bbcb..4b2828a6e81c134b077e64f171e78c760d0994a9 100644 (file)
@@ -1,5 +1,5 @@
 use support::{project, execs, main_file, basic_bin_manifest};
-use hamcrest::{assert_that, existing_dir, is_not};
+use hamcrest::{assert_that, existing_dir, existing_file, is_not};
 
 fn setup() {
 }
@@ -30,3 +30,60 @@ test!(different_dir {
                 execs().with_status(0).with_stdout(""));
     assert_that(&p.build_dir(), is_not(existing_dir()));
 });
+
+test!(clean_multiple_packages {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+
+            [dependencies.d1]
+                path = "d1"
+            [dependencies.d2]
+                path = "d2"
+
+            [[bin]]
+                name = "foo"
+        "#)
+        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
+        .file("d1/Cargo.toml", r#"
+            [package]
+            name = "d1"
+            version = "0.0.1"
+            authors = []
+
+            [[bin]]
+                name = "d1"
+        "#)
+        .file("d1/src/main.rs", "fn main() { println!(\"d1\"); }")
+        .file("d2/Cargo.toml", r#"
+            [package]
+            name = "d2"
+            version = "0.0.1"
+            authors = []
+
+            [[bin]]
+                name = "d2"
+        "#)
+        .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }");
+    p.build();
+
+    assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2")
+                                        .arg("-p").arg("foo"),
+                execs().with_status(0));
+
+    assert_that(&p.bin("foo"), existing_file());
+    assert_that(&p.build_dir().join("debug").join("deps").join("d1"), existing_file());
+    assert_that(&p.build_dir().join("debug").join("deps").join("d2"), existing_file());
+
+    assert_that(p.cargo("clean").arg("-p").arg("d1").arg("-p").arg("d2")
+                                .cwd(&p.root().join("src")),
+                execs().with_status(0).with_stdout(""));
+    assert_that(&p.bin("foo"), existing_file());
+    assert_that(&p.build_dir().join("debug").join("deps").join("d1"),
+                is_not(existing_file()));
+    assert_that(&p.build_dir().join("debug").join("deps").join("d2"),
+                is_not(existing_file()));
+});